﻿using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Practices.EnterpriseLibrary.Validation;
using Microsoft.Practices.EnterpriseLibrary.Validation.Validators; 


namespace PSE.Framework.Service.Validation
{
    /// <summary>
    /// Classe para validações de comparação entre valores
    /// </summary>
    internal class ValueComparisonValidator : Validator<IComparable> 
    {

        /// <summary>
        /// Valor para comparação
        /// </summary>
        private IComparable _valueToCompare;

        /// <summary>
        /// Tipo de comparação
        /// </summary>
        private ComparisonType _comparisonType;

        /// <summary>
        /// Construtor
        /// </summary>
        /// <param name="valueToCompare">Valor para comparar</param>
        /// <param name="comparisonType">Tipo de comparação</param>
        public ValueComparisonValidator(IComparable valueToCompare, ComparisonType comparisonType) 
            : base(null, null)
        {
            _valueToCompare = valueToCompare; 
            _comparisonType = comparisonType; 
        }


        /// <summary>
        /// Método de implementação requerida (abstract na classe base) que contém a regra de validação 
        /// </summary>
        /// <param name="objectToValidate"></param>
        /// <param name="currentTarget"></param>
        /// <param name="key"></param>
        /// <param name="validationResults"></param>
        protected override void DoValidate(IComparable objectToValidate, object currentTarget, string key, ValidationResults validationResults)
        {
            int compareResult;
            bool validado;

            if (objectToValidate != null && _valueToCompare != null)
            {
                AdjustCompareValueType(objectToValidate);
                compareResult = objectToValidate.CompareTo(_valueToCompare);

                switch (_comparisonType)
                {
                    case ComparisonType.Equal:
                        validado = (compareResult == 0);
                        break;
                    case ComparisonType.GreaterThan:
                        validado = (compareResult > 0);
                        break;
                    case ComparisonType.GreaterThanEqual:
                        validado = (compareResult >= 0);
                        break;
                    case ComparisonType.LessThan:
                        validado = (compareResult > 0);
                        break;
                    case ComparisonType.LessThanEqual:
                        validado = (compareResult <= 0);
                        break;
                    case ComparisonType.NotEqual:
                        validado = (compareResult != 0);
                        break;
                    default:
                        validado = false;
                        break;
                }
            }
            else
            {
                // Se ambos são nulos, só é válido se tipo for Equal
                if (objectToValidate == null && _valueToCompare == null)
                {
                    validado = (_comparisonType == ComparisonType.Equal);
                }
                else // um é nulo e o outro não, então são obrigatoriamente diferentes, 
                {
                    // Neste caso, só valida se tipo for NotEqual
                    validado = (_comparisonType == ComparisonType.NotEqual); 
                }
            }

            if (!validado)
            {
                validationResults.AddResult(new ValidationResult(this.MessageTemplate, currentTarget, key, this.Tag, this));   
            }
        }

        /// <summary>
        /// Método para ajustar o tipo do valor a ser comparado de acordo com o tipo do objeto a ser validado
        /// </summary>
        /// <param name="objectToValidate"></param>
        private void AdjustCompareValueType(IComparable objectToValidate)
        {
            if (objectToValidate != null)
            {
                if (_valueToCompare.GetType() != objectToValidate.GetType())
                {
                    _valueToCompare = (IComparable)Convert.ChangeType(_valueToCompare, objectToValidate.GetType());
                }
            }
        }


        /// <summary>
        /// Método de implementação requerida (abstract na classe base) e que retorna DefaultMessageTemplate
        /// </summary>
        protected override string DefaultMessageTemplate
        {
            get { return ""; }
        }
    }
}
